# -*- coding : utf_8 -*-
"""
=======================================
Time : 2025/3/22 9:48
Author : 田霄汉
Email : 522989570@qq.com
File : assert_util.py
Project : pytest_demo
=======================================
"""

import operator
import jsonpath
from utils.log_util import logs
from utils.mysql_util import MysqlUtil


class AssertUtil:

    """
    接口断言模式封装
    1、数据库断言
    2、状态码和相等断言
    3、不相等断言
    4、包含断言
    """

    @classmethod
    def database_assert(cls, value):
        """
        数据库断言
        :param value: sql查询语句
        :return: flag
        """
        flag = 0
        db_result = MysqlUtil().get_select_mysql(value)
        if not db_result:
            flag += 1
            logs.error("数据库断言失败")
        return flag

    @classmethod
    def statuscode_assert(cls, value, return_code):
        """
        状态码断言
        :param value:
        :param return_code: 实际返回状态码
        :return: flag
        """
        flag = 0
        if not isinstance(value, int):
            value = int(value)
            if value != return_code:
                flag = + 1
                logs.error("状态码断言失败")
        return flag

    @classmethod
    def equals_assert(cls, value, sj_result):
        """
        相等断言
        :param value: validate中的equals值
        :param sj_result: 实际返回值
        :return: flag
        """
        flag = 0
        for assert_key, assert_value in value.items():
            lists = jsonpath.jsonpath(sj_result, '$..%s' % assert_key)
            # validate中equals中的key存在实际返回结果中
            if lists:
                # validate中equals中的key对应的value没有在实际响应结果中
                if assert_value not in lists:
                    flag = flag + 1
                    logs.error("相等断言失败")
            # validate中equals中的key没有在实际返回结果中
            else:
                flag = flag + 1
                logs.error(f"相等断言失败：返回的结果{assert_key}不存在")
        return flag

    @classmethod
    def unequals_assert(cls, value, sj_result):
        """
        不相等断言
        :param value: validate中的unequals值
        :param sj_result: 接口实际返回值
        :return: flag
        """
        flag = 0
        if isinstance(value, dict) and isinstance(sj_result, dict):
            # 找出预期结果与实际结果之间的key值
            common_key = list(value.keys() & sj_result.keys())
            if common_key:
                common_key = common_key[0]
                new_sj_result = {common_key: sj_result[common_key]}
                eq_assert = operator.ne(new_sj_result, value)
                if not eq_assert:
                    flag += 1
                    logs.error('不相等断言失败')
        return flag

    @classmethod
    def contains_assert(cls, value, sj_result):
        flag = 0
        # validate中contains对应的value没有在实际返回结果中
        if value not in str(sj_result):
            flag = flag + 1
            logs.error('包含断言失败')
        return flag

    @classmethod
    def assert_result(cls, YamlValidate, sj_result, return_code):
        all_flag = 0
        try:
            for yq in YamlValidate:
                for key, value in yq.items():
                    if key == "database":
                        flag = cls.database_assert(value)
                        all_flag = all_flag + flag
                    elif key == "status_code":
                        flag = cls.statuscode_assert(value, return_code)
                        all_flag = all_flag + flag
                    elif key == "equals":
                        flag = cls.equals_assert(value, sj_result)
                        all_flag = all_flag + flag
                    elif key == "unequals":
                        flag = cls.unequals_assert(value, sj_result)
                        all_flag = all_flag + flag
                    elif key == 'contains':
                        flag = cls.contains_assert(value, sj_result)
                        all_flag = all_flag + flag
                    else:
                        logs.warning(f'框架暂不支持{key}断言方式')
            if all_flag == 0:
                logs.info('断言成功')
            assert all_flag == 0
        except Exception as e:
            logs.error(f'断言报错信息：{e}')
